{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(70, 101) (70, 1) (31, 101) (31, 1)\n"
     ]
    }
   ],
   "source": [
    "data = np.genfromtxt('example.dat', delimiter = ',')\n",
    "# 选择特征与标签\n",
    "x = data[:,0:100] \n",
    "y = data[:,100].reshape(-1,1)\n",
    "# 加一列\n",
    "X = np.column_stack((np.ones((x.shape[0],1)),x))\n",
    "\n",
    "# 划分训练集与测试集\n",
    "X_train, y_train = X[:70], y[:70]\n",
    "X_test, y_test = X[70:], y[70:]\n",
    "print(X_train.shape, y_train.shape, X_test.shape, y_test.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义参数初始化函数\n",
    "def initialize(dims):\n",
    "    w = np.zeros((dims, 1))\n",
    "    b = 0\n",
    "    return w, b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义ridge损失函数\n",
    "def l2_loss(X, y, w, b, alpha):\n",
    "    num_train = X.shape[0]\n",
    "    num_feature = X.shape[1]\n",
    "    y_hat = np.dot(X, w) + b\n",
    "    loss = np.sum((y_hat-y)**2)/num_train + alpha*(np.sum(np.square(w)))\n",
    "    dw = np.dot(X.T, (y_hat-y)) /num_train + 2*alpha*w\n",
    "    db = np.sum((y_hat-y)) /num_train\n",
    "    return y_hat, loss, dw, db"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义训练过程\n",
    "def ridge_train(X, y, learning_rate=0.01, epochs=300):\n",
    "    loss_list = []\n",
    "    w, b = initialize(X.shape[1])\n",
    "    for i in range(1, epochs):\n",
    "        y_hat, loss, dw, db = l2_loss(X, y, w, b, 0.1)\n",
    "        w += -learning_rate * dw\n",
    "        b += -learning_rate * db\n",
    "        loss_list.append(loss)\n",
    "        \n",
    "        if i % 100 == 0:\n",
    "            print('epoch %d loss %f' % (i, loss))\n",
    "        params = {\n",
    "            'w': w,\n",
    "            'b': b\n",
    "        }\n",
    "        grads = {\n",
    "            'dw': dw,\n",
    "            'db': db\n",
    "        }\n",
    "    return loss, loss_list, params, grads"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch 100 loss 1.272892\n",
      "epoch 200 loss 0.918566\n",
      "epoch 300 loss 0.824857\n",
      "epoch 400 loss 0.786619\n",
      "epoch 500 loss 0.767618\n",
      "epoch 600 loss 0.757040\n",
      "epoch 700 loss 0.750696\n",
      "epoch 800 loss 0.746687\n",
      "epoch 900 loss 0.744053\n"
     ]
    }
   ],
   "source": [
    "# 执行训练示例\n",
    "loss, loss_list, params, grads = ridge_train(X_train, y_train, 0.01, 1000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'w': array([[-0.04196546],\n",
       "        [-0.10129988],\n",
       "        [ 0.39150459],\n",
       "        [ 0.27116379],\n",
       "        [ 0.14453605],\n",
       "        [ 0.64205522],\n",
       "        [-0.11777636],\n",
       "        [ 0.63100371],\n",
       "        [-0.24612371],\n",
       "        [-0.01809963],\n",
       "        [-0.0098817 ],\n",
       "        [ 0.59860774],\n",
       "        [ 0.05109339],\n",
       "        [ 0.57323775],\n",
       "        [ 0.0717013 ],\n",
       "        [-0.2494207 ],\n",
       "        [ 0.05841939],\n",
       "        [ 0.34882372],\n",
       "        [-0.05196151],\n",
       "        [ 0.59741259],\n",
       "        [ 0.07360193],\n",
       "        [-0.00804983],\n",
       "        [-0.08417487],\n",
       "        [ 0.38967928],\n",
       "        [-0.02238394],\n",
       "        [-0.05105738],\n",
       "        [-0.04475576],\n",
       "        [-0.04810095],\n",
       "        [-0.05424062],\n",
       "        [ 0.36298941],\n",
       "        [ 0.09421072],\n",
       "        [ 0.12947524],\n",
       "        [ 0.12975187],\n",
       "        [ 0.13770473],\n",
       "        [-0.11610581],\n",
       "        [-0.03832583],\n",
       "        [ 0.07592514],\n",
       "        [-0.05664576],\n",
       "        [-0.01481198],\n",
       "        [-0.13093971],\n",
       "        [-0.03888878],\n",
       "        [ 0.04806379],\n",
       "        [ 0.07572836],\n",
       "        [ 0.02141963],\n",
       "        [-0.0614007 ],\n",
       "        [ 0.06729191],\n",
       "        [ 0.04008781],\n",
       "        [-0.10963405],\n",
       "        [ 0.01420552],\n",
       "        [ 0.16873802],\n",
       "        [ 0.0224207 ],\n",
       "        [-0.15348103],\n",
       "        [ 0.14905584],\n",
       "        [ 0.01561819],\n",
       "        [-0.02441497],\n",
       "        [-0.03295334],\n",
       "        [ 0.25312019],\n",
       "        [-0.04258556],\n",
       "        [-0.29287108],\n",
       "        [-0.29727421],\n",
       "        [ 0.24557737],\n",
       "        [ 0.09651535],\n",
       "        [ 0.08340742],\n",
       "        [ 0.10361739],\n",
       "        [ 0.15327439],\n",
       "        [-0.13955045],\n",
       "        [ 0.03098354],\n",
       "        [-0.08871406],\n",
       "        [-0.1399495 ],\n",
       "        [ 0.34909413],\n",
       "        [ 0.25747902],\n",
       "        [-0.06286765],\n",
       "        [ 0.1647463 ],\n",
       "        [ 0.33578424],\n",
       "        [ 0.15741705],\n",
       "        [ 0.21992387],\n",
       "        [-0.00607112],\n",
       "        [-0.17332475],\n",
       "        [ 0.14796202],\n",
       "        [ 0.08563692],\n",
       "        [ 0.07206544],\n",
       "        [ 0.26622856],\n",
       "        [-0.13541505],\n",
       "        [-0.0260657 ],\n",
       "        [ 0.01670993],\n",
       "        [-0.13668085],\n",
       "        [-0.19075803],\n",
       "        [-0.02781821],\n",
       "        [ 0.22166602],\n",
       "        [-0.26971977],\n",
       "        [-0.12248242],\n",
       "        [-0.08364962],\n",
       "        [ 0.31015334],\n",
       "        [ 0.1617263 ],\n",
       "        [ 0.11999462],\n",
       "        [ 0.04892356],\n",
       "        [-0.12183373],\n",
       "        [ 0.16720899],\n",
       "        [ 0.08939526],\n",
       "        [-0.24464656],\n",
       "        [ 0.15278414]]), 'b': -0.12715818630193307}"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 获取训练参数\n",
    "params"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-0.07363409],\n",
       "       [-2.23904964],\n",
       "       [ 1.35392332],\n",
       "       [-2.21912506],\n",
       "       [-2.56515114]])"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 定义预测函数\n",
    "def predict(X, params):\n",
    "    w = params['w']\n",
    "    b = params['b']\n",
    "    \n",
    "    y_pred = np.dot(X, w) + b\n",
    "    return y_pred\n",
    "\n",
    "y_pred = predict(X_test, params)\n",
    "y_pred[:5]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0.24671],\n",
       "       [-4.25711],\n",
       "       [ 2.38642],\n",
       "       [-1.87815],\n",
       "       [-3.41362]])"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_test[:5]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-0.6338800998887384"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.metrics import r2_score\n",
    "r2_score(y_pred, y_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 简单绘图\n",
    "import matplotlib.pyplot as plt\n",
    "f = X_test.dot(params['w']) + params['b']\n",
    "\n",
    "plt.scatter(range(X_test.shape[0]), y_test)\n",
    "plt.plot(f, color = 'darkorange')\n",
    "plt.xlabel('X')\n",
    "plt.ylabel('y')\n",
    "plt.show();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 训练过程中的损失下降\n",
    "plt.plot(loss_list, color = 'blue')\n",
    "plt.xlabel('epochs')\n",
    "plt.ylabel('loss')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sklearn Lasso intercept : [-0.238]\n",
      "\n",
      "sklearn Lasso coefficients :\n",
      " [ 0.    -0.     0.598  0.642  0.     1.007 -0.     0.818 -0.228  0.\n",
      "  0.     0.794  0.     0.741 -0.    -0.125 -0.     0.794  0.     0.819\n",
      "  0.     0.    -0.     0.567 -0.    -0.    -0.    -0.    -0.     0.495\n",
      "  0.     0.     0.     0.    -0.    -0.    -0.    -0.    -0.    -0.\n",
      "  0.    -0.     0.    -0.    -0.008  0.     0.    -0.    -0.     0.02\n",
      "  0.    -0.     0.    -0.     0.    -0.068  0.246  0.    -0.042 -0.\n",
      "  0.105  0.032  0.     0.     0.    -0.    -0.     0.    -0.     0.125\n",
      "  0.234 -0.     0.     0.169  0.     0.016  0.    -0.     0.     0.\n",
      " -0.     0.201 -0.    -0.     0.    -0.041 -0.107 -0.     0.024 -0.108\n",
      " -0.    -0.     0.123  0.     0.    -0.059 -0.     0.094 -0.    -0.178\n",
      "  0.066]\n",
      "\n",
      "sklearn Lasso number of iterations : 24\n"
     ]
    }
   ],
   "source": [
    "# 导入线性模型模块\n",
    "from sklearn import linear_model\n",
    "# 创建lasso模型实例\n",
    "sk_lasso = linear_model.Lasso(alpha=0.1)\n",
    "# 对训练集进行拟合\n",
    "sk_lasso.fit(X_train, y_train)\n",
    "# 打印模型相关系数\n",
    "print(\"sklearn Lasso intercept :\", sk_lasso.intercept_)\n",
    "print(\"\\nsklearn Lasso coefficients :\\n\", sk_lasso.coef_)\n",
    "print(\"\\nsklearn Lasso number of iterations :\", sk_lasso.n_iter_)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
